<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/ol.min.css"
    integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer" />
  <title>编辑图形</title>

  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    html,
    body,
    #app,
    .app-map {
      height: 100%;
      height: 100%;
    }

    .app-btns {
      position: fixed;
      right: 10px;
      top: 10px;
      background-color: #fff;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
      width: 210px;
      padding: 25px;
      text-align: center;
      border-radius: 5px;
      display: flex;
      flex-direction: column;
      z-index: 2;
    }

    .app-btns button {
      font-size: 18px;
      border: none;
      padding: 12px 20px;
      border-radius: 4px;
      color: #fff;
      background-color: #409eff;
      border-color: #409eff;
      cursor: pointer;
      border: 1px solid #dcdfe6;
      margin-bottom: 5px;
    }

    .app-btns button:hover {
      background: #66b1ff;
      border-color: #66b1ff;
    }

    .app-btns button.active {
      background-color: #07c160;
    }

    [v-cloak] {
      display: none;
    }
  </style>

</head>

<body>
  <div id="app" v-cloak>
    <div class="app-map" id="app-map"></div>
    <div class="app-btns">
      <button type='button' :class="{active: item.id === currentId}" v-for='item in drawTypes'
        @click='handleClickDraw(item)'>{{item.text}}</button>
      <button type='button' @click='handleClickExit' style="background-color: #808080;">退出绘制</button>
      <button type='button' @click='handleClickDelete' style="background-color: #ff0000;">删除所有图形</button>
      <button type='button' @click='verifyMode = !verifyMode'
        :style="{'background-color': verifyMode ? '#ff0000' : '#409eff'}"
        title="开启验证问题模式后，先在地图上绘制一个图形，记住图形边或者端点的位置。点击删除图形，鼠标靠近记住的边或者点的位置">验证删除图形问题</button>
    </div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/dist/ol.min.js"
    integrity="sha512-xXS2hdEzrUC2BFO0fIJ+d/bwScOLgN+W7psE4XXq6xULXjKFCskUNe8QOVVUsB7vtYRI5ZS0Ie4EgS4VzJQBkQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js"
    integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>

  <script>
    const drawingStyle = '';
    const attributions = '<a href="https://ditu.amap.com/" target="_blank">&copy; 地图版权归高德地图所有</a>';
    const { createApp } = Vue;
    const userType = 0;
    let zIndex = 1;
    const vm = createApp({
      data() {
        return {
          map: {}, // 地图实例
          drawSource: {}, // 绘制图形的图层资源
          draw: null, // 绘制实例
          modify: null,
          currentId: -1, // 当前绘制类型id
          features: [], // 绘制的图形数组
          drawTypes: [
            {
              type: 'Point',
              text: '打点',
              id: 2
            },
            {
              type: 'Circle',
              text: '画圆',
              id: 1
            },
            {
              type: 'Polygon',
              text: '画多边形',
              id: 3
            },
            {
              type: 'LineString',
              text: '画折线',
              id: 5
            },
            {
              type: 'Circle',
              text: '正方形',
              geometryFunction: ol.interaction.Draw.createRegularPolygon(4),
              id: 7
            },
            {
              type: 'Circle',
              text: '矩形',
              geometryFunction: ol.interaction.Draw.createBox(),
              id: 6
            }],
          verifyMode: false
        }
      },
      methods: {
        // 初始化地图
        initMap() {
          // 创建放置用户绘制的feature的图层
          this.drawSource = new ol.source.Vector();
          const layer = new ol.layer.Vector({
            source: this.drawSource
          });
          // 高德地图瓦片地址
          const mianLayer = new ol.layer.Tile({
            source: new ol.source.XYZ({
              attributions: attributions,
              url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
            })
          });
          //  初始化地图
          this.map = new ol.Map({
            target: 'app-map',
            layers: [mianLayer, layer],
            view: new ol.View({
              projection: 'EPSG:3857',
              center: ol.proj.transform([111.8453154, 32.7383500], 'EPSG:4326', 'EPSG:3857'),
              zoom: 5
            }),
            controls: ol.control.defaults.defaults({
              attribution: true, // 地图版权信息工具
              attributionOptions: {
                collapsed: false, // 默认折叠
                collapsible: true // 是否可折叠，显示折叠按钮
              }
            })
          });
          // 绑定地图事件
          this.bindMapEvt();
          // 创建modify
          this.createModify();
        },
        // 绑定地图事件
        bindMapEvt() {
          // 监听鼠标点击
          this.map.on('click', (evt) => {
            const coordinate = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
            console.log('当前点击坐标为 : ' + coordinate[0].toFixed(7) + ',' + coordinate[1].toFixed(7));
          });
        },
        // 创建modify
        createModify(deltetFirst) {
          // 删除feature后，将Modify也删除
          if (deltetFirst) {
            this.map.removeInteraction(this.modify);
          };
          console.log('重新创建了，Modify');
          // 创建Modify
          this.modify = new ol.interaction.Modify({
            source: this.drawSource,
            // 进行编辑的触发条件，默认点击左键。
            condition: (event) => {
              // 鼠标左键即可编辑
              return ol.events.condition.primaryAction(event);
              // 按住shift键+鼠标左键进行编辑
              // return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.primaryAction(event);
            },
            // 删除端点的条件，默认是alt+鼠标左键点击端点，端点就被删除了
            deleteCondition: function (event) {
              // 双击端点，将端点删除
              return ol.events.condition.doubleClick(event);
            },
            // 插入端点的条件，就是在直线中间进行编辑，能否拉出来一个新的端点。默认是可以，可设置成组合键，也可以根据业务自行设置，最后返回true或者false即可
            insertVertexCondition: function (event) {
              // 鼠标左键即可插入新的端点
              return ol.events.condition.primaryAction(event);
              // 用户类型是0的，可插入新的端点
              // return userType === 0;
              // ctrl+鼠标左键可插入新的端点
              // return ol.events.condition.platformModifierKey(event) && ol.events.condition.primaryAction(event);
            },
          });
          // 绑定修改结束的事件
          this.modify.on('modifyend', (evt) => {
            console.log('编辑结束了，modifyend', evt);
            evt.features.forEach(feature => {
              this.setFeatureStyle(feature);
            })
          });
          // 将Modify添加到地图
          this.map.addInteraction(this.modify);
        },
        // 点击绘制各种图形
        handleClickDraw(item) {
          const { type, geometryFunction, id } = item;
          // 同一种类型点击，不处理
          if (this.currentId === id) {
            return;
          }
          this.currentId = id;
          // 根据 type 创建交互
          this.draw = new ol.interaction.Draw({
            source: this.drawSource,
            type: type,
            geometryFunction: geometryFunction,
            style: new ol.style.Style({
              image: new ol.style.Icon({
                src: drawingStyle,
                scale: 0.2,
                // anchor: [0.5, 0.5],
                rotateWithView: true,
                rotation: 0,
                opacity: 1
              }),
              stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
              fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 })
            })
          });
          // 将交互添加到地图
          this.map.addInteraction(this.draw);
          // 监听绘制完成的事件
          this.draw.on('drawend', (event) => {
            // 存储绘制的feature
            this.features.push(event.feature);
            // 设置随机颜色样式
            this.setFeatureStyle(event.feature);
            // 结束此次绘制
            this.map.removeInteraction(this.draw);
            // 恢复按钮状态
            this.currentId = -1;
          });
        },
        // 设置feature样式 为随机颜色
        setFeatureStyle(feature) {
          feature.setStyle(new ol.style.Style({
            stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
            fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
            image: new ol.style.Circle({
              radius: 10,
              fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8) }),
              stroke: new ol.style.Stroke({
                color: '#' + Math.random().toString(16).slice(2, 8),
                width: 2
              })
            }),
            // 保证编辑的结束后处于上层
            zIndex: ++zIndex
          }));
        },
        // 退出绘制
        handleClickExit() {
          this.currentId = -1;
          this.draw && this.map.removeInteraction(this.draw);
          this.draw = null;
        },
        // 点击删除图形
        handleClickDelete() {
          // 删除用户创建的feature
          for (let i = 0; i < this.features.length; i++) {
            this.drawSource.removeFeature(this.features[i]);
          };
          this.features = [];
          // 将Modify删除，再重新创建Modify
          !this.verifyMode && this.createModify(true);
        }
      },
      mounted() {
        this.initMap();
      }
    }).mount('#app')
  </script>

</body>

</html>